﻿// =====================================================================
//
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
// =====================================================================
#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Xrm.Sdk.XmlNamespaces;

#endregion

namespace Microsoft.Xrm.Sdk.Client.Protocols.Policy
{
	internal static class AuthPolicyConstants
	{
		internal const string MsXrm = "ms-xrm";
		internal const string MsXrmAuthentication = "//" + MsXrm + ":Authentication";
		internal const string MsXrmSecureTokenServiceMsXrmIdentifier = "//" + MsXrm + ":SecureTokenService/" + MsXrm + ":Identifier";
		internal const string MsXrmLiveTrust = "//" + MsXrm + ":LiveTrust/";
		internal const string MsXrmOrgTrust = "//" + MsXrm + ":OrgTrust/";

		internal const string AuthenticationPolicy = "AuthenticationPolicy";

		internal const string AppliesTo = "AppliesTo";
		internal const string TrustVersion = "TrustVersion";
		internal const string SecurityMode = "SecurityMode";
		internal const string LivePolicy = "LivePolicy";

		internal const string AuthenticationType = "AuthenticationType";
		internal const string SecureTokenServiceIdentifier = "SecureTokenServiceIdentifier";

		internal const string LiveIdAppliesTo = "LiveIdAppliesTo";
		internal const string LiveTrustTrustVersion = "LiveTrustTrustVersion";
		internal const string LiveTrustSecurityMode = "LiveTrustSecurityMode";
		internal const string LiveTrustLivePolicy = "LiveTrustLivePolicy";
		internal const string LiveTrustLiveIdAppliesTo = "LiveTrustLiveIdAppliesTo";
		internal const string LiveEndpoint = "LiveEndpoint";

		internal const string OrgIdAppliesTo = "OrgIdAppliesTo";
		internal const string OrgIdTrustTrustVersion = "OrgIdTrustTrustVersion";
		internal const string OrgIdTrustSecurityMode = "OrgIdTrustSecurityMode";
		internal const string OrgIdPolicy = "OrgIdPolicy";
		internal const string OrgIdDeviceAppliesTo = "OrgIdDeviceAppliesTo";
		internal const string OrgIdEndpoint = "OrgIdEndpoint";
		internal const string Identifier = "Identifier";
		internal const string OrgIdIdentifier = "OrgIdIdentifier";
	}

	public sealed class AuthenticationPolicyImporter : ServicePolicyImporter, IPolicyImporter
	{
		#region IPolicyImporter Members

		public Boolean CanImport(XDocument document)
		{
			if (!Imported)
			{
				IEnumerable<XElement> bindingElements =
					from el in document.Descendants(PublicNamespaces.MSXRM + AuthPolicyConstants.AuthenticationPolicy)
					select el;
				return bindingElements.Count() > 0;
			}
			return false;
		}

		public ServicePolicy ImportPolicy(XDocument document)
		{
			return ImportR8Policy(document) ?? ImportLegacyPolicy(document);
		}

		private ServicePolicy ImportLegacyPolicy(XDocument document)
		{
			IEnumerable<XElement> bindingElements =
				from el in document.Descendants(PublicNamespaces.MSXRM + AuthPolicyConstants.AuthenticationPolicy)
				select el;
			foreach (XElement bindingElement in bindingElements)
			{
				AuthenticationPolicy xrmPolicyBindingElement = new AuthenticationPolicy();
				ExtractValue(xrmPolicyBindingElement, bindingElement, AuthPolicyConstants.AuthenticationType,
							 PublicNamespaces.MSXRM + "Authentication");

				XElement sts = bindingElement.Element(PublicNamespaces.MSXRM + "SecureTokenService");
				if (sts != null)
				{
					ExtractValue(xrmPolicyBindingElement, sts, AuthPolicyConstants.SecureTokenServiceIdentifier,
								 PublicNamespaces.MSXRM + AuthPolicyConstants.Identifier);
				}

				ExtractLiveTrustElements(xrmPolicyBindingElement, sts);

				Imported = true;
				return xrmPolicyBindingElement;
			}
			return null;
		}

		private ServicePolicy ImportR8Policy(XDocument document)
		{
			IEnumerable<XElement> bindingElements =
				from el in document.Descendants(PublicNamespaces.MSXRM2012 + AuthPolicyConstants.AuthenticationPolicy)
				select el;
			foreach (XElement bindingElement in bindingElements)
			{
				AuthenticationPolicy xrmPolicyBindingElement = new AuthenticationPolicy();
				ExtractValue(xrmPolicyBindingElement, bindingElement, AuthPolicyConstants.AuthenticationType,
							 PublicNamespaces.MSXRM2012 + "Authentication");

				XElement sts = bindingElement.Element(PublicNamespaces.MSXRM2012 + "SecureTokenService");
				if (sts != null)
				{
					ExtractValue(xrmPolicyBindingElement, sts, AuthPolicyConstants.SecureTokenServiceIdentifier,
								 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.Identifier);
				}

				ExtractOrgIdTrustElements(xrmPolicyBindingElement, sts);

				Imported = true;
				return xrmPolicyBindingElement;
			}
			return null;
		}

		private void ExtractLiveTrustElements(AuthenticationPolicy xrmPolicyBindingElement, XElement sts)
		{
			XElement liveTrust = sts.Element(PublicNamespaces.MSXRM + "LiveTrust");
			if (liveTrust != null)
			{
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.AppliesTo, PublicNamespaces.MSXRM + AuthPolicyConstants.AppliesTo);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.LiveTrustTrustVersion,
							 PublicNamespaces.MSXRM + AuthPolicyConstants.TrustVersion);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.LiveTrustSecurityMode,
							 PublicNamespaces.MSXRM + AuthPolicyConstants.SecurityMode);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.LiveTrustLivePolicy,
							 PublicNamespaces.MSXRM + AuthPolicyConstants.LivePolicy);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.LiveTrustLiveIdAppliesTo,
							 PublicNamespaces.MSXRM + AuthPolicyConstants.LiveIdAppliesTo);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.LiveEndpoint,
							 PublicNamespaces.MSXRM + AuthPolicyConstants.LiveEndpoint);
			}
		}

		private void ExtractOrgIdTrustElements(AuthenticationPolicy xrmPolicyBindingElement, XElement sts)
		{
			XElement liveTrust = sts.Element(PublicNamespaces.MSXRM2012 + "OrgTrust");
			if (liveTrust != null)
			{
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdAppliesTo, PublicNamespaces.MSXRM2012 + AuthPolicyConstants.AppliesTo);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdTrustTrustVersion,
							 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.TrustVersion);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdTrustSecurityMode,
							 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.SecurityMode);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdPolicy,
							 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.LivePolicy);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdDeviceAppliesTo,
							 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.LiveIdAppliesTo);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdEndpoint,
							 PublicNamespaces.MSXRM2012 + AuthPolicyConstants.LiveEndpoint);
				ExtractValue(xrmPolicyBindingElement, liveTrust, AuthPolicyConstants.OrgIdIdentifier,
							PublicNamespaces.MSXRM2012 + AuthPolicyConstants.Identifier);
			}
		}

		#endregion
	}


	public sealed class AuthenticationPolicy : ServicePolicy
	{
		public string SecureTokenServiceIdentifier
		{
			get
			{
				if (this.PolicyElements.ContainsKey(AuthPolicyConstants.SecureTokenServiceIdentifier))
				{
					return this.PolicyElements[AuthPolicyConstants.SecureTokenServiceIdentifier];
				}
				else
				{
					return null;
				}
			}
		}
	}
}
